# -*- coding: utf-8 -*-
import json
import os

from PyQt5 import QtCore, QtGui, QtWidgets, Qt
from PyQt5.QtGui import QIcon, QDoubleValidator
from PyQt5.QtWidgets import QDockWidget, QAction, QFileDialog, QGroupBox, QGridLayout
import cv2
import numpy as np
import copy
from imageManager import *
import matplotlib.pylab as plt
from module.position.pyzernikemoment import Zernikemoment
PARA_PATH = os.path.dirname(__file__)


class positionGui(QtWidgets.QWidget):
    update_para_signal = QtCore.pyqtSignal(int, dict)
    para = dict()
    index = 0

    def __init__(self, parent=None):
        super(positionGui, self).__init__(parent)
        self.imgMat = None
        self.n = 0
        self.m = 0
        self.Z = 0
        self.A = 0
        self.Phi = 0

    def initPara(self):
        parafile = os.path.join(PARA_PATH, "module_para.json")
        with open(parafile, "r", encoding='utf-8') as f:
            self.para = json.loads(f.read())

    def setPara(self, index, para):
        self.index = index
        if para is None:
            return
        if para["version"] == self.para["version"]:
            self.para = copy.deepcopy(para)
            self.roi_en.setChecked(self.para["roi"]["enable"] == 1)
            self.x_value.setValue(self.para["roi"]["x"])
            self.y_value.setValue(self.para["roi"]["y"])
            self.w_value.setValue(self.para["roi"]["w"])
            self.h_value.setValue(self.para["roi"]["h"])
            self.m_value.setValue(self.para["moment"]["m"])
            self.m_value.setValue(self.para["moment"]["n"])
            filename = self.lineEdit_register.text()
            if os.path.exists(filename):
                src = cv2.imread(filename, cv2.IMREAD_COLOR)
                src = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
                self.Z, self.A, self.Phi = Zernikemoment(src, self.n, self.m)

    def initUI(self):
        self.initPara()
        label_register = QtWidgets.QLabel()
        label_register.setText("RegisterPicture:")
        self.lineEdit_register = QtWidgets.QLineEdit(self)
        pushButton_open = QtWidgets.QPushButton(self)
        pushButton_open.setText("open")
        pushButton_open.clicked.connect(self.open_file)

        hlayout1 = QtWidgets.QHBoxLayout()
        hlayout1.addWidget(label_register)
        hlayout1.addWidget(self.lineEdit_register)
        hlayout1.addWidget(pushButton_open)

        grid_moment = QGridLayout()
        m_label = QtWidgets.QLabel("m:")
        self.m_value = QtWidgets.QSpinBox(self)
        n_label = QtWidgets.QLabel("n:")
        self.n_value = QtWidgets.QSpinBox(self)
        grid_moment.addWidget(n_label, 1, 0)
        grid_moment.addWidget(self.n_value, 1, 1)
        grid_moment.addWidget(m_label, 2, 0)
        grid_moment.addWidget(self.m_value, 2, 1)
        groupBox_moment = QGroupBox("Moment:")
        groupBox_moment.setLayout(grid_moment)

        areaMinLabel = QtWidgets.QLabel()
        areaMinLabel.setText("area minimum:")
        self.areaMinText = QtWidgets.QSpinBox(self)
        self.areaMinText.setMaximum(2147483647)
        self.areaMinText.setSingleStep(1)
        self.areaMinText.valueChanged.connect(self.setMinValue)

        hlayout_area1 = QtWidgets.QHBoxLayout()
        hlayout_area1.addWidget(areaMinLabel)
        hlayout_area1.addWidget(self.areaMinText)

        areaMaxLabel = QtWidgets.QLabel()
        areaMaxLabel.setText("area maximum:")
        self.areaMaxText = QtWidgets.QSpinBox(self)
        self.areaMaxText.setMaximum(2147483647)
        self.areaMaxText.setSingleStep(1)
        self.areaMaxText.valueChanged.connect(self.setMaxValue)

        hlayout_area2 = QtWidgets.QHBoxLayout()
        hlayout_area2.addWidget(areaMaxLabel)
        hlayout_area2.addWidget(self.areaMaxText)

        grid = QGridLayout()
        en_lable = QtWidgets.QLabel("enable")
        self.roi_en = QtWidgets.QCheckBox(self)
        x_label = QtWidgets.QLabel("x:")
        self.x_value = QtWidgets.QSpinBox(self)
        y_label = QtWidgets.QLabel("y:")
        self.y_value = QtWidgets.QSpinBox(self)
        w_label = QtWidgets.QLabel("w:")
        self.w_value = QtWidgets.QSpinBox(self)
        h_label = QtWidgets.QLabel("h:")
        self.h_value = QtWidgets.QSpinBox(self)
        grid.addWidget(en_lable, 0, 0)
        grid.addWidget(self.roi_en, 0, 1)
        grid.addWidget(x_label, 1, 0)
        grid.addWidget(self.x_value, 1, 1)
        grid.addWidget(y_label, 2, 0)
        grid.addWidget(self.y_value, 2, 1)
        grid.addWidget(w_label, 1, 2)
        grid.addWidget(self.w_value, 1, 3)
        grid.addWidget(h_label, 2, 2)
        grid.addWidget(self.h_value, 2, 3)
        groupBox = QGroupBox("Region of Interest:")
        groupBox.setLayout(grid)

        btn_apply = QtWidgets.QPushButton()
        btn_apply.setText("apply")

        btn_ok = QtWidgets.QPushButton(self)
        btn_ok.setText("ok")
        btn_ok.clicked.connect(self.btn_ok_clicked)

        btn_cancel = QtWidgets.QPushButton(self)
        btn_cancel.setText("cancel")
        btn_cancel.clicked.connect(self.btn_cancel_clicked)
        hbox_common = QtWidgets.QHBoxLayout()
        hbox_common.addWidget(btn_ok)
        hbox_common.addWidget(btn_cancel)

        vlayout = QtWidgets.QVBoxLayout(self)
        vlayout.addLayout(hlayout1, 1)
        vlayout.addLayout(hlayout_area1)
        vlayout.addLayout(hlayout_area2)
        vlayout.addWidget(groupBox_moment)
        vlayout.addWidget(groupBox)
        vlayout.addStretch(1)
        vlayout.addWidget(btn_apply)
        vlayout.addLayout(hbox_common)
        btn_apply.clicked.connect(self.btn_apply_clicked)
        self.x_value.setRange(0, 65535)
        self.y_value.setRange(0, 65535)
        self.w_value.setRange(0, 65535)
        self.h_value.setRange(0, 65535)
        self.x_value.valueChanged.connect(self.x_value_changed)
        self.y_value.valueChanged.connect(self.y_value_changed)
        self.w_value.valueChanged.connect(self.w_value_changed)
        self.h_value.valueChanged.connect(self.h_value_changed)
        self.m_value.valueChanged.connect(self.m_value_changed)
        self.n_value.valueChanged.connect(self.n_value_changed)
        self.roi_en.stateChanged.connect(self.enable_value_changed)

    def open_file(self):
        filename = QFileDialog.getOpenFileName(self, "Open file", "..", "Image files(*.bmp *.jpg *.gif *.png *.jpeg)")
        if filename[0]:
            self.lineEdit_register.setText(filename[0])

    def setMinValue(self):
        self.para["area"]["min"] = self.areaMinText.value()

    def setMaxValue(self):
        self.para["area"]["max"] = self.areaMaxText.value()

    def zoneChange(self, zone):
        self.para["roi"]["x"] = zone[0]
        self.para["roi"]["y"] = zone[1]
        self.para["roi"]["w"] = zone[2]
        self.para["roi"]["h"] = zone[3]
        self.drawROI()
        self.x_value.setValue(self.para["roi"]["x"])
        self.y_value.setValue(self.para["roi"]["y"])
        self.w_value.setValue(self.para["roi"]["w"])
        self.h_value.setValue(self.para["roi"]["h"])

    def enable_value_changed(self):
        if self.roi_en.isChecked():
            self.para["roi"]["enable"] = 1
        else:
            self.para["roi"]["enable"] = 0
        self.drawROI()

    def x_value_changed(self):
        self.para["roi"]["x"] = self.x_value.value()
        self.drawROI()

    def y_value_changed(self):
        self.para["roi"]["y"] = self.y_value.value()
        self.drawROI()

    def w_value_changed(self):
        self.para["roi"]["w"] = self.w_value.value()
        self.drawROI()

    def h_value_changed(self):
        self.para["roi"]["h"] = self.h_value.value()
        self.drawROI()

    def m_value_changed(self):
        self.para["moment"]["m"] = self.m_value.value()

    def n_value_changed(self):
        self.para["roi"]["n"] = self.n_value.value()

    def drawROI(self):
        if self.para["roi"]["enable"] == 0:
            return
        img = img_mng.getOriginMat()
        if len(img.shape) == 3:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        else:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        x = self.para["roi"]["x"]
        y = self.para["roi"]["y"]
        w = self.para["roi"]["w"]
        h = self.para["roi"]["h"]
        cv2.rectangle(self.imgMat, (x, y), (x + w, y + h), (0, 255, 0), 5)
        img_mng.dispImg(self.imgMat)

    def btn_apply_clicked(self):
        img = img_mng.getOriginMat()
        if img is None:
            return
        if len(img.shape) == 3:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        else:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        enable = self.para["roi"]["enable"]
        if enable == 1:
            x = self.para["roi"]["x"]
            y = self.para["roi"]["y"]
            w = self.para["roi"]["w"]
            h = self.para["roi"]["h"]

            mask = np.zeros_like(img_mng.img)
            mask[y:(y + h), x:(x + w)] = 255
            imgray = cv2.bitwise_and(img_mng.img, mask)
        else:
            imgray = img_mng.img
        # filename = self.lineEdit_register.text()
        # print(filename)
        # if os.path.exists(filename):
        #     src = cv2.imread(filename, cv2.IMREAD_COLOR)
        #     src = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
        #     self.Z, self.A, self.Phi = Zernikemoment(src, self.n, self.m)
        # img_mng.showImg("masked.jpg", imgray)
        # self.imgMat = cv2.cvtColor(src , cv2.COLOR_GRAY2RGB)
        # img_mng.showImg("src", self.imgMat)
        # gray = cv2.bitwise_not(src)
        contours, hierarchy = cv2.findContours(imgray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        len_contours = len(contours)
        area_min = self.para["area"]["min"]
        area_max = self.para["area"]["max"]
        for i in range(len_contours):
            #area (center, (w,h, angle))
            # cv2.polylines(self.imgMat, [pts], 1, (0,255,0),3)
            area = cv2.contourArea(contours[i])
            if area_min < area < area_max:
                # color format: (B G R)
                # cv2.drawContours(self.imgMat, contours, i, (0, 0, 255), 5)
                # ret = cv2.minEnclosingCircle(contours[i])
                # print("minEnclosingCircle:((x,y),radius)", ret)
                mask = np.zeros_like(imgray)
                # rect = cv2.minAreaRect(contours[i])
                # box = np.int64(cv2.boxPoints(rect))
                # pts = box.reshape((-1, 1, 2))
                # cv2.fillPoly(mask, [pts], 255)
                cv2.fillPoly(mask, [contours[i]], 255)
                gray = cv2.bitwise_and(imgray, mask)
                n=4
                m=2
                Z, A, Phi = Zernikemoment(gray, n, m)
                print(Z, A, Phi)
                img_mng.showImg("img", mask)
                points = len(contours[i])
                if points < 5:
                    continue
                e1 = cv2.getTickCount()
                ret = cv2.fitEllipse(contours[i])
                e2 = cv2.getTickCount()
                time = (e2 - e1) / cv2.getTickFrequency()
                print("fitEllipse:(center, width, height, angle)", ret)
                print("elapse time:", time*1000, "ms")
        img_mng.dispImg(self.imgMat)

    def btn_ok_clicked(self):
        self.para["moment"]["m"] = int(self.m_value.value())
        self.para["moment"]["n"] = int(self.n_value.value())
        self.update_para_signal.emit(self.index, self.para)

    def btn_cancel_clicked(self):
        self.close()

    def run(self, para):
        img = img_mng.getOriginMat()
        if img is None:
            return
        if len(img.shape) == 3:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        else:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        enable = para["roi"]["enable"]
        if enable == 1:
            x = para["roi"]["x"]
            y = para["roi"]["y"]
            w = para["roi"]["w"]
            h = para["roi"]["h"]

            mask = np.zeros_like(img_mng.img)
            mask[y:(y + h), x:(x + w)] = 255
            imgray = cv2.bitwise_and(img_mng.img, mask)
        else:
            imgray = img_mng.img
        contours, hierarchy = cv2.findContours(imgray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        len_contours = len(contours)
        area_min = para["area"]["min"]
        area_max = para["area"]["max"]
        for i in range(len_contours):
            area = cv2.contourArea(contours[i])
            if area_min < area < area_max:
                e1 = cv2.getTickCount()
                mask = np.zeros_like(imgray)
                cv2.fillPoly(mask, [contours[i]], 255)
                gray = cv2.bitwise_and(imgray, mask)
                n=para["moment"]["n"]
                m=para["moment"]["m"]
                Z, A, Phi = Zernikemoment(gray, n, m)
                e2 = cv2.getTickCount()
                time = (e2 - e1) / cv2.getTickFrequency()
                print("zernike:", Z, A, Phi)
                print("elapse time:", time*1000, "ms")
        img_mng.dispImg(self.imgMat)



if __name__ == "__main__":
    import sys
    #
    # n = 4
    # m = 2
    # print('------------------------------------------------')
    #
    # print('Calculating Zernike moments ..., n = %d, m = %d' % (n, m))
    # fig, axes = plt.subplots(2, 3)
    #
    # imgs = ['example/Oval_H.png', 'example/Oval_45.png', 'example/Oval_V.png']
    # for i in range(3):
    #     src = cv2.imread(imgs[i], cv2.IMREAD_COLOR)
    #     src = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    #     Z, A, Phi = Zernikemoment(src, n, m)
    #     axes[0, i].imshow(plt.imread(imgs[i]))
    #     axes[0, i].axis('off')
    #     title = 'A = ' + str(round(A, 4)) + '\nPhi = ' + str(round(Phi, 4))
    #     axes[0, i].set_title(title)
    #
    # imgs = ['example/Shape_0.png', 'example/Shape_90.png', 'example/Rectangular_H.png']
    # for i in range(3):
    #     src = cv2.imread(imgs[i], cv2.IMREAD_COLOR)
    #     src = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    #     Z, A, Phi = Zernikemoment(src, n, m)
    #     axes[1, i].imshow(plt.imread(imgs[i]))
    #     axes[1, i].axis('off')
    #     title = 'A = ' + str(round(A, 4)) + '\nPhi = ' + str(round(Phi, 4))
    #     axes[1, i].set_title(title)
    # print('Calculation is complete')
    #
    # plt.show()
    app = QtWidgets.QApplication(sys.argv)
    ui = positionGui()
    ui.initUI()
    ui.show()
    sys.exit(app.exec_())
